use moss::from_meta::FromMeta;
use moss_expand::derive::from_meta::expand;
use quote::ToTokens;
// use moss_expand::derive::from_meta::expand;
use syn::{DeriveInput, LitInt, LitStr, Path, parse_quote};

#[test]
fn unit() {
    #[derive(Debug, FromMeta)]
    #[name("s")]
    pub struct S;
}

#[test]
fn test_expand() {
    let input: DeriveInput = parse_quote! {
        #[name("status_code")]
        pub struct StatusCodeAttr {
            pub status: Option<LitInt>,
            pub code: Option<LitStr>,
            pub cause: Option<LitStr>,
        }
    };

    let token = expand(&input).unwrap();
    println!("{}", token);
}

#[test]
fn test_from_attrs_expand() {
    let input: DeriveInput = parse_quote! {
        pub struct VariantAttrs {
            pub status_code: Option<StatusCodeAttr>,
        }
    };

    let token = moss_expand::derive::from_attrs::expand(&input).unwrap();
    println!("{}", token);
}

#[test]
fn tuple() {
    #[derive(FromMeta)]
    pub struct Len(LitInt, LitInt);
    let input: DeriveInput = parse_quote! {
        #[len(23, 25)]
        pub struct Len(LitInt, Option<LitInt>);
    };
    for attr in &input.attrs {
        let len = Len::try_from(attr).unwrap();
        let v1: i32 = len.0.base10_parse().unwrap();
        println!("{v1}");
        let v2 = len.1.base10_digits();
        println!("{v2}");
    }
}

#[test]
fn name_value() {
    #[derive(FromMeta)]
    pub struct Student {
        pub name: Option<String>,
        pub age: i32,
    }

    let input: DeriveInput = parse_quote! {
        pub struct Student {
            pub name: Option<String>,
            pub age: i32,
        }
    };

    let token = expand(&input).unwrap();
    println!("{}", token);

    for attr in &input.attrs {
        let student = Student::try_from(attr).unwrap();
        println!("{:?}", student.name);
        println!("{:?}", student.age);
    }
}

#[test]
fn enumer() {
    #[derive(FromMeta)]
    pub struct Student {
        pub name: Option<String>,
        pub age: i32,
    }

    #[derive(FromMeta)]
    enum Error {
        // #[strip]
        S(Student),
        R(LitInt, Option<LitStr>),
    }

    let input: DeriveInput = parse_quote! {
        #[error(s(student(name = "zhangsan", age = 18)))]
        // #[error(r(13, "abc"))]
        enum Error {
            #[strip]
            S(Student),

            R(LitInt, LitStr),
        }
    };

    // let token = expand(&input).unwrap();
    // println!("{}", token);

    for attr in &input.attrs {
        let error = Error::try_from(attr).unwrap();
        match error {
            Error::S(student) => {
                println!("{:?}", student.name);
                println!("{:?}", student.age);
            }
            Error::R(lit_int, lit_str) => {
                println!("{:?}", lit_int.base10_parse::<i32>().unwrap());
                println!("{:?}", lit_str.is_some());
            }
        }
    }
}

#[test]
fn enumer2() {
    #[derive(FromMeta)]
    pub struct Student {
        pub name: Option<String>,
        pub age: i32,
        pub error: Error,
        pub tuple: Tuple,
    }

    #[derive(FromMeta)]
    #[strip]
    pub struct Tuple(pub Path);

    #[derive(Debug, FromMeta)]
    #[strip]
    enum Error {
        Name,
        Path,
    }

    let input: DeriveInput = parse_quote! {
        #[student(name = "zhangsan", age = 18, error(path), tuple(ttt))]
        enum Error {
            #[strip]
            S(Student),

            R(LitInt, LitStr),
        }
    };

    // let token = expand(&input).unwrap();
    // println!("{}", token);

    for attr in &input.attrs {
        let student = Student::try_from(attr).unwrap();
        println!("{:?}", student.name);
        println!("{:?}", student.age);
        println!("{:?}", student.error);
        println!("{:?}", student.tuple.0.to_token_stream().to_string());
    }
}

#[test]
pub fn enumer3() {
    let input: DeriveInput = parse_quote! {
        #[name("validate")]
        pub enum FieldAttr {
            Skip,
            Length(Expr, Expr),
            Range(Expr, Expr),
            Regex(String),
            Enumer(Type),

            #[strip]
            Default,
        }
    };
    let result = expand(&input).unwrap();
    println!("{}", result);
}

#[test]
fn one_field() {
    let input: DeriveInput = parse_quote! {

        #[strip]
        pub struct ReflectAttr {
            pub owner_ty: Path,
        }

    };

    let token = expand(&input).unwrap();
    println!("{}", token);
}
